home *** CD-ROM | disk | FTP | other *** search
- Path: beach.and.nl!usenet
- From: jos@and.nl (Jos A. Horsmeier)
- Newsgroups: comp.lang.c
- Subject: Re: Got Questions About Multi-Dimension Arrays (After Reading FAQ)
- Date: 1 Feb 1996 11:26:31 GMT
- Organization: AND Operations Research B.V.
- Distribution: world
- Message-ID: <4eq817$icr@beach.and.nl>
- References: <4ep87b$o60@alcor.usc.edu>
- NNTP-Posting-Host: klepzeiker.and.nl
- Mime-Version: 1.0
- Content-Type: Text/Plain; charset=ISO-8859-1
- X-Newsreader: WinVN 0.99.5
-
- In article <4ep87b$o60@alcor.usc.edu>, wawda@alcor.usc.edu wrote:
-
- |I read questions 6.19 and 6.20 from the FAQ that deal with
- |multi-dimensional arrays but am still confused. If someone can clear
- |up my confusion, I would really appreciate it. Bascailly I still don't
- |see why it isn't possible to do this:
- |
- |void myfunc(int *array,int rows,int cols)
- |{
- | printf("%d\n",array[1][1]);
- |}
- |
- |and call the function like this:
- |
- |int m[2][2] = {1, 2, 3, 4};
- |
- |myfunc(m,2,2);
- |
- |If I understand correctly, a multideminsional array is really stored
- |continguously like this in memory:
- |
- |array[0][0] | 1 | memory address a
- |array[0][1] | 2 | memory address a+sizeof(int)
- |array[1][0] | 3 | ....
- |array[1][1] | 4 | ....
- |
- |So why can't C convert from pointer to integer to a multidemsional
- |array. The reason I want to do this is because my function needs to
- |take in an array of any width and height. Thank you for your time,
-
- I know, it's confusing; especially if you don't know what's happening
- deep down at the bottom. Let's start at the bottom and figure out what's
- really going on there:
-
- int i;
-
- Object 'i' is declared (and defined) to be an integer object. Whenever
- we use 'i', we get back an integral valued object. Here's one step up:
-
- int *ip;
-
- Object 'ip' can point to an integer object; I used to explain this as:
- 'ip is one star (dereference) away from an int'. If ip points to i:
-
- ip= i;
-
- then object ip contains a value and nobody is actually supposed to know
- what this value really is; all that suffices is that 'ip points to i'.
- The value of object ip is 'one star away of an int', so:
-
- *ip
-
- is an int, and because ip happens to point to i, *ip happens to be the
- value of i. Let's introduce a bunch of ints:
-
- int ai[A_BUNCH]= { 0, 1, 2, ... A_BUNCH-1 };
-
-
- C guarantees that the value of ai is just 'one star away from an int', so:
-
- ai
-
- points to an int, and to be more specific, it points to the first int
- of the entire bunch of ints, i.e. it points to ai[0], so:
-
- *ai
-
- equals ai[0]. and the statements:
-
- int *ip= ai;
-
- ip++;
-
- make ip point to the next int in the bunch, i.e. *ip == ai[1].
-
- Let's introduce a lot of bunches of ints:
-
- int aai[A_LOT][A_BUNCH] = { { 0, 1, 2, ... A_BUNH-1 },
- { A_BUNCH, ... 2*A_BUNCH-1 },
- ... ...
- { ... A_LOT*A_BUNCH-1 }
- };
-
- The value of aai is 'one star away from a bunch of ints', i.e. aai
- points to the first bunch of ints: aai[0] (the first row of the matrix).
-
- Let's get back to your function:
-
- void myfunc(int *array,int rows,int cols)
- {
- printf("%d\n",array[1][1]);
- }
-
- If we call this function as:
-
- myfunc(aai, A_LOT, A_BUNCH);
-
- we implicitely cast an object, a 'thing' that points to a bunch of ints
- (aai) to an object type that is supposed to point to an int. Remember:
-
- int* array;
-
- declares 'array' to be a thing that is 'one star away from an int',
- while 'aai' happens to be 'one star away from a bunch of ints'.
- Now what is the expression:
-
- array[1][1]
-
- supposed to be then? If 'array' is 'one star away from an int' then
-
- array[1]
-
- yields a value equal to:
-
- array++;
- *array;
-
- So array[1] is an int already; but then, the expression:
-
- array[1][1]
-
- must be read as:
-
- <some int value>[1]
-
- and this doesn't make sense. Definitely the declaration of the parameter
- 'array' is wrong here. We want 'array' not te be 'one star away from an int',
- but we want it to 'one star away from a bunch of ints'. Here goes:
-
- void myfunc(int (*array)[A_BUNCH],int rows,int cols)
- {
- printf("%d\n",array[1][1]);
- }
-
- Please note the expicit parentheses here. This declaration reads:
-
- 'array' is a pointer ('one star away') from a bunch of ints.
-
- Everything seems to be fine now, but there's one disappointment coming
- up: we've explicitely told the compiler that object 'array' points to
- a bunch of ints and the actual value of 'bunch' is known at compile time,
- i.e. to make the examples above work, we need something like:
-
- #define A_BUNCH 42
-
- somehwere near the top of the source code file. We cannot supply the
- number of columns, i.e. the value of A_BUNCH, during runtime. C is
- just a silly little language -- it does not support real dynamic arrays.
-
- There's a workaround though: we want array[0] point to the first bunch
- of ints, array[1] must point to the second bunch, and so on, up till
- array[A_LOT-1], which must point to the last bunch of ints and we want
- to specify what 'a bunch' and 'a lot' is during runtime. This is where
- malloc() and friends come in -- if C is too silly to handle dynamic
- arrays, we'll hack 'em together ourselves (isn't that what programming
- is all about? ;-) Here goes:
-
- int **array;
-
- The object 'array' is 'two stars away from an int', so array[0], array[1],
- etc. are 'one star away from an int'.
-
- Have a look at this:
-
- array= malloc(A_LOT*sizeof(int*));
-
- if malloc succeeds, object 'array' now points a A_LOT of things that
- are all 'one star away from an int'. Here's a lot of bunches of ints:
-
- int* temp= malloc(A_LOT*A_BUCH*sizeof(int));
-
- and 'temp' (which is not important here, it just exists for the sake of
- the example) points to all of them. Let's make all the array[i] objects
- point to their own bunch of ints:
-
- int i;
-
- for (i= 0; i < A_LOT; i++)
- array[i]= &(temp[i*A_BUNCH]);
-
- This is what happened:
-
- array 0 1 2 A_BUNCH-1
- +---+ +---+---+---+ +---+
- 0 | ------------>| | | | ...... | |
- +---+ +---+---+---+ +---+
- 1 | ------------>| | | | ...... | |
- +---+ +---+---+---+ +---+
- ... ... ...... ...
- +---+ +---+---+---+ +---+
- A_LOT-1 | ------------>| | | | ...... | |
- +---+ +---+---+---+ +---+
-
- And now the expression
-
- array[1][1]
-
- points to the second int in the second bunch of ints, because the
- expression
-
- array[1]
-
- is one star away from a bunch of ints, and the expression
-
- array
-
- is one star away from a lot of bunches of ints.
-
- We can generalize the above observations and fiddle-diddle the following
- function:
-
-
- void* mat_alloc(int rows, int cols, int size) {
-
- char** mat = malloc(rows*sizeof(char*));
- char* temp= malloc(rows*cols*size);
-
- int i;
-
- for (i= 0; i < rows; i++)
- mat[i]= &(temp[i*cols]);
-
- return mat;
-
- }
-
- All you have to do now, is:
-
- int** m= mat_alloc(2, 2, sizeof(1));
-
- which makes object m 'one star away from two things that are one star away
- from two ints', i.e. m[1][1] does exactly what you had in mind. We do have
- to change your function a bit though:
-
- void myfunc(int **array,int rows,int cols)
- {
- printf("%d\n",array[1][1]);
- }
-
- (note the two '*'s in the declaration of parameter 'array'). To complete
- the example, this is how one gets rid of matrix m again:
-
- void mat_free(void* mat) {
-
- char** temp= mat;
-
- if (temp)
- free(*temp);
-
- free(temp);
-
- }
-
- Does this help you out a bit?
-
- kind regards,
-
- Jos aka jos@and.nl
- --
- Atnwgqkrl gy zit vgksr, ug qshiqwtzoeqs!
-
-